package com.example.lkfy.Interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.lkfy.model.RequestLimit;
import com.example.lkfy.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * 请求限流拦截器
 */
@Slf4j
@Component
public class RequestLimitInterceptor implements HandlerInterceptor {
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public  boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            //判断接口是否添加requestLimit
            if(handlerMethod.hasMethodAnnotation(RequestLimit.class)){
                RequestLimit requestLimit = handlerMethod.getMethod().getAnnotation(RequestLimit.class);
                JSONObject object = new JSONObject();
                String token = request.getParameter(requestLimit.name());
                response.setContentType("text/json;charset=utf-8");
                object.put("timestamp", System.currentTimeMillis());
                BoundValueOperations<String, Integer> boundValueOperations = redisTemplate.boundValueOps(token);
                if(StringUtils.isEmpty(token)){
                    object.put("result", "token is invalid");
                    response.getWriter().print(JSON.toJSONString(object));
                } else if(checkLimit(token,requestLimit)){
                    object.put("result","token is success,请求成功");
                     long expire = boundValueOperations.getExpire();
                    return true;
                }else {
                    object.put("result", "达到访问次数上限，禁止访问!");
                    response.getWriter().print(JSON.toJSONString(object));
                }
                return false;
            }
        }
        return true;
    }

    /**
     * 限速校验
     * @param token
     * @param limit
     * @return
     */
    private Boolean checkLimit(String token, RequestLimit limit){
        BoundValueOperations<String , Integer> boundValueOperations = redisTemplate.boundValueOps(token);
        Integer count  = boundValueOperations.get();
        if(Objects.isNull(count)){
            redisTemplate.boundValueOps(token).set(1,limit.timeout(), limit.timeUnit());
        }else if(count > limit.limitTimes()){
            return Boolean.FALSE;
        }else {
            redisTemplate.boundValueOps(token).set(++count, boundValueOperations.getExpire(),limit.timeUnit());
        }
        return  Boolean.TRUE;
    }
}
